//
//  MSMacro.h
//  OrderingMerchantsSide
//
//  Created by iOS on 2018/9/19.
//  Copyright © 2018年 mls. All rights reserved.
//
//  -----------------------------------------------------------------------------------------------------
//  历代iPhone的分辨率
//  设备                                          尺寸         分辨率           大小
//  iPhone 2G/3/3GS                             320 x 480   320 x 480       3.5英寸
//  iPhone 4/4S                                 320 x 480   640 x 960       3.5英寸
//  iPhone 5/5S/5C/SE1                          320 x 568   640 x 1136      4.0英寸
//  iPhone 6/6S/7/8/SE2                         375 x 667   750 x 1334      4.7英寸
//  iPhone 6P/7P/8P                             414 x 736   1080 x 1920     5.5英寸 *
//  iPhine X/XS/11 Pro                          375 x 812   1125 x 2436     5.8英寸
//  iPhone XR/11                                414 x 896   828 x 1792      6.1英寸
//  iPhone XS Max/11 Pro Max                    414 x 896   1242 x 2688     6.5英寸 *
//  iPhone 12 mini/13 mini                      360 x 780   1080 x 2340     5.4英寸
//  iPhone 12/12 Pro/13/13 Pro/14               390 x 844   1170 x 2532     6.1英寸
//  iPhone 12 Pro Max/13 Pro Max/14 Plus        428 x 926   1284 x 2778     6.7英寸
//  iPhone 14 Pro/15/15 Pro                     393 x 852   1179 x 2556     6.1英寸
//  iPhone 14 Pro Max/15 Plus/15 Pro Max        428 x 926   1290 x 2796     6.7英寸
//  -----------------------------------------------------------------------------------------------------
//  屏幕高宽比
//  设备     高宽比                                                               比例     (近似)
//  iPhone  2G/3/3GS/4/4S                                                       1.50    2 : 3
//  iPhone  5/5S/5C/SE                                                          1.77    9 : 16
//  iPhone  6/6S/7/8                                                            1.77    9 : 16
//  iPhone  6/6S/7/8 Plus                                                       1.77    9 : 16

//  iPhone  X/XR/XS/XS Max                                                      2.16    9 : 20
//  iPhone  11/11 Pro/11 Pro Max                                                2.16    9 : 20
//  iPhone  12/12 Mini/12 Pro/12 Pro Max                                        2.16    9 : 20
//  iPhone  13/13 Plus/13 Pro/13 Pro Max                                        2.16    9 : 20
//  iPhone  14/14 Plus                                                          2.16    9 : 20
//  iPhone  14 Pro/14 Pro Max                                                   2.17    9 : 20
//  iPhone  15/15 Plus/15 Pro/15 Pro Max                                        2.17    9 : 20
//  -----------------------------------------------------------------------------------------------------



#ifndef MSMacro_h
#define MSMacro_h
#import <UIKit/UIKit.h>

#define MS_APP_DELEGATE    [[UIApplication sharedApplication] delegate]


#pragma mark - 沙盒路径
/**
 * Documents/    保存应用程序的重要数据文件和用户数据文件等。用户数据基本上都放在这个位置(例如从网上下载的图片或音乐文件)，该文件夹在应用程序更新时会自动备份，在连接iTunes时也可以自动同步备份其中的数据；
 该目录的内容被iTunes和iCloud备份。
 * Library/    这个目录下有两个子目录,可创建子文件夹。可以用来放置您希望被备份但不希望被用户看到的数据。该路径下的文件夹，除Caches以外，都会被iTunes备份；
 该目录的内容被iTunes和iCloud备份
 * Library/Caches    保存应用程序使用时产生的支持文件和缓存文件(保存应用程序再次启动过程中需要的信息)，还有日志文件最好也放在这个目录；
 iTunes 不会备份该目录，并且该目录下数据可能被其他工具清理掉。
 * Library/Preferences    保存应用程序的偏好设置文件。NSUserDefaults类创建的数据和plist文件都放在这里；
 该目录的内容被iTunes和iCloud备份。
 * Tmp/    使用此目录可以编写在应用程序启动之间不需要保留的临时文件，您的应用程序应在不再需要时删除此目录中的文件，但是，当您的应用未运行时，系统可能会清除此目录；
 iTunes或iCloud不会备份此目录下的内容。
 */

/** app沙盒的根目录（home） */
#define ms_pathOfAppHome  NSHomeDirectory()
/** 根目录路径Directory，用于存储用户数据，该文件夹在应用程序更新时会自动备份，在连接iTunes时也可以自动同步备份其中的数据，该目录的内容被iTunes和iCloud备份 */
#define ms_pathOfDocument [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
/** 根目录路径Library，这个目录下有两个子目录,可创建子文件夹。可以用来放置您希望被备份但不希望被用户看到的数据。该路径下的文件夹，除Caches以外，都会被iTunes备份，该目录的内容被iTunes和iCloud备份 */
#define ms_pathOfLibrary  [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject]
/** 根目录路径Caches，保存应用程序使用时产生的支持文件和缓存文件(保存应用程序再次启动过程中需要的信息)，还有日志文件最好也放在这个目录，iTunes 不会备份该目录，并且该目录下数据可能被其他工具清理掉 */
#define ms_pathOfCache    [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]
/** 临时文件路径，用于存放临时文件，这个可以放一些当APP退出后不再需要的文件 */
#define ms_pathOfTemp     NSTemporaryDirectory()
#define ms_accountPath    [ms_pathOfCache stringByAppendingPathComponent:@"Account.data"]


#pragma mark - NSUserDefaults
/** userDefault */
#define MS_USER_DEFAULT        [NSUserDefaults standardUserDefaults]


#pragma mark - 设备相关信息 版本号、屏幕尺寸、比例换算
/** pad */
#define MS_IS_PAD (UI_USER_INTERFACE_IDIOM()== UIUserInterfaceIdiomPad)
/** iPhone X判断 */
#define MS_IS_IPHONEX  ({ \
BOOL iPhoneX = NO; \
if (@available(iOS 11.0, *)) { \
    if ([UIApplication sharedApplication].windows[0].safeAreaInsets.bottom > 0) { \
        iPhoneX = YES; \
    } \
} \
iPhoneX; \
})
/** 刘海屏判断 */
#define IS_BANGS_SCREEN             ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? ((int)((UIScreen.mainScreen.bounds.size.height / UIScreen.mainScreen.bounds.size.width) * 100) == 216) : NO) 
#define MS_SYSTEM_VERSION           [[UIDevice currentDevice].systemVersion floatValue]
/** 屏幕宽 */
#define MS_SCREEN_WIDTH             [UIScreen mainScreen].bounds.size.width
/** 屏幕高 */
#define MS_SCREEN_HEIGHT            [UIScreen mainScreen].bounds.size.height
/** 顶部的安全距离 */
#define MS_SAFE_AREA_TOP_HEIGHT     (BOTTOM_SAFE_AREA_HEIGHT == 0 ? 0.0 : 24.0)
/** 底部的安全距离 */
#define MS_SAFE_AREA_BOTTOM_HEIGHT  (MS_IS_IPHONEX ? 34.0 : 0.0)
/** 状态栏高度 */
#define MS_STATUS_BAR_HEIGHT        (MS_IS_IPHONEX ? 44.0 : 20.0)
/** 导航栏高度 */
#define MS_NAV_BAR_HEIGHT           (MS_IS_IPHONEX ? 88.0 : 64.0)
/** tabbar高度 */
#define MS_TAB_BAR_HEIGHT           (MS_SAFE_AREA_BOTTOM_HEIGHT + 49.0)
#define MS_IOS9_AND_LATER           (MS_SYSTEM_VERSION >= 9.0)
#define MS_IOS11_AND_LATER          (MS_SYSTEM_VERSION >= 11.0)
/** iPhone4或iPhone5 */
#define MS_IS_IPHONE4_OR_IPHONE5    MS_SCREEN_HEIGHT <= 568.0
/** 适配比例，/ˌædæpˈteɪʃn/ */
#define MS_ADAPTATION_RATIO         MS_SCREEN_WIDTH / 750.0


#pragma mark - layout
/** 立即更新约束 */
static inline void ms_updateViewLayout(UIView *view)
{
    [view setNeedsUpdateConstraints];
    [view updateConstraintsIfNeeded];
    [view setNeedsLayout];
    [view layoutIfNeeded];
}


#pragma mark - 字体
/** 字号适配 */
static inline CGFloat FontSize(CGFloat fontSize)
{
    if (MS_SCREEN_WIDTH == 320)
    {
        if (fontSize >= 30)
        {
            return fontSize - 3.5;
        }
        else
        {
            return fontSize - 2;
        }
    }
    else if (MS_SCREEN_WIDTH == 375)
    {
        return fontSize;
    }
    else
    {
        return fontSize + 1.5;
    }
}

#define MS_BOLD_SYSTEM_FONT_OF_SIZE(FONTSIZE)    [UIFont boldSystemFontOfSize:FontSize(FONTSIZE)]
#define MS_SYSTEM_FONT_OF_SIZE(FONTSIZE)            [UIFont systemFontOfSize:FontSize(FONTSIZE)]
#define MS_FONT(NAME, FONTSIZE)                     [UIFont fontWithName:(NAME) size:(FONTSIZE)]


#pragma mark - 颜色
/** 随机色 */
#define MS_RANDOM_COLOR                        [UIColor colorWithRed:arc4random()%((255-1+1)+1)/255.0 green:arc4random()%((255-1+1)+1)/255.0 blue:arc4random()%((255-1+1)+1)/255.0 alpha:1.0]
/** RGBA */
#define MS_RGBA_COLOR(r,g,b,a)                 [UIColor colorWithRed:(r) / 255.0 green:(g) / 255.0 blue:(b) / 255.0 alpha:(a)]
/** RGB */
#define MS_RGB_COLOR(r,g,b)                    MS_RGBA_COLOR(r,g,b,1)
/** 16进制转RGB */
#define MS_HEX_COLOR(HEX)                      [UIColor colorWithRed:((float)((HEX & 0xFF0000) >> 16))/255.0 green:((float)((HEX & 0xFF00) >> 8))/255.0 blue:((float)(HEX & 0xFF))/255.0 alpha:1.0f]
/** 16进制转RGB */
#define MS_HEX_COLOR_AND_ALPHA(HEX, ALPHA)     [UIColor colorWithRed:((float)((HEX & 0xFF0000) >> 16)) / 255.0 green:((float)((HEX & 0xFF00) >> 8)) / 255.0 blue:((float)(HEX & 0xFF)) / 255.0 alpha:ALPHA]

#pragma mark - image
//获取图片资源
/** 图片 */
#define MS_IMAGE_NAMED(name)                   [UIImage imageNamed:name]


#pragma mark - 字符串处理
/** 转换为字符串 */
#define MS_TEXT_STRING(x)                      [NSString stringWithFormat:@"%@", x]
#define MS_VALID_STRING(string, defaultString) [NSString stringWithFormat:@"%@", ms_objectIsEmpty(string) ? defaultString : string]
/** 文本大小 */
#define ms_heightOfText(text, font, width)     [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : font} context:nil].size.height
#define ms_sizeOfText(text, font)              [text boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : font} context:nil].size


#pragma mark - 判空
/** 字符串是否为空 */
#define ms_stringIsEmpty(str) ([str isKindOfClass:[NSNull class]] || str == nil || [str length] < 1 ? YES : NO )
/** 数组是否为空 */
#define ms_arrayIsEmpty(array) (array == nil || [array isKindOfClass:[NSNull class]] || array.count == 0)
/** 字典是否为空 */
#define ms_dictIsEmpty(dic) (dic == nil || [dic isKindOfClass:[NSNull class]] || dic.allKeys == 0)
/** 是否是空对象 */
#define ms_objectIsEmpty(_object) (_object == nil \
|| [_object isKindOfClass:[NSNull class]] \
|| ([_object respondsToSelector:@selector(length)] && [(NSData *)_object length] == 0) \
|| ([_object respondsToSelector:@selector(count)] && [(NSArray *)_object count] == 0))


#pragma mark - log
#ifdef DEBUG
#define MSLog(...) printf("~~~~~~~~~\n%s %s 第%d行\n%s\n",__TIME__, __PRETTY_FUNCTION__ ,__LINE__, [[NSString stringWithFormat:__VA_ARGS__] UTF8String]);
#else
#define MSLog(...)
#endif


#pragma mark - main queue
#ifndef ms_dispatch_main_async_safe
/** 异步主线程 */
#define ms_dispatch_main_async_safe(block)\
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0)\
{\
block();\
}\
else\
{\
dispatch_async(dispatch_get_main_queue(), block);\
}
#endif


#pragma mark - global queue
#ifndef ms_dispatch_global_async_safe
/** 异步全局线程 */
#define ms_dispatch_global_async_safe(block)\
dispatch_async(dispatch_get_global_queue(0, 0), block);
#endif


#pragma mark - 单例
// .h
#define ms_interface(class) + (instancetype)shared##class;
// .m
#define ms_implementation(class) \
static class *_instance; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
        _instance = [super allocWithZone:zone]; \
    }); \
\
    return _instance; \
} \
\
+ (instancetype)shared##class \
{ \
    if (_instance == nil) { \
        _instance = [[class alloc] init]; \
    } \
\
    return _instance; \
}\
- (id)copyWithZone:(NSZone *)zone \
{ \
    return _instance; \
}


#pragma mark - notification center
/** 添加消息监听 */
#define ms_addObserver(observer, aSelector, aName, anObject) [[NSNotificationCenter defaultCenter] addObserver:observer selector:aSelector name:aName object:anObject]
/** 移除消息监听 */
#define ms_removeObserver(observer, aName, anObject) [[NSNotificationCenter defaultCenter] removeObserver:observer name:aName object:anObject]
/** 发送消息 */
#define ms_postNotification(aName, anObject, aUserInfo) [[NSNotificationCenter defaultCenter] postNotificationName:aName object:anObject userInfo:aUserInfo]


#pragma mark - 角度、弧度转换
/** 由角度获取弧度 */
#define ms_degreesToRadians(x)      (M_PI * (x) / 180.0)
/** 由弧度获取角度 */
#define ms_radianToDegrees(radian)  (radian*180.0)/(M_PI)


#pragma mark - 归档接档runtime实现
#import <objc/runtime.h>
#define ms_codingImplementation \
- (void)encodeWithCoder:(NSCoder *)coder \
{ \
    unsigned int count = 0; \
    Ivar *ivars = class_copyIvarList([self class], &count); \
    for (int i = 0; i<count; i++) { \
        Ivar ivar = ivars[i]; \
        const char *name = ivar_getName(ivar); \
        NSString *key = [NSString stringWithUTF8String:name]; \
        [coder encodeObject:[self valueForKey:key] forKey:key]; \
    } \
    free(ivars); \
} \
\
- (instancetype)initWithCoder:(NSCoder *)coder \
{ \
    self = [super init]; \
    if (self) { \
        unsigned int count = 0; \
        Ivar *ivars = class_copyIvarList([self class], &count); \
        for (int i = 0; i<count; i++) { \
            Ivar ivar = ivars[i]; \
            const char *name = ivar_getName(ivar); \
            NSString *key = [NSString stringWithUTF8String:name]; \
            id value = [coder decodeObjectForKey:key]; \
            [self setValue:value forKey:key]; \
        } \
        free(ivars); \
    } \
    return self; \
}


#pragma mark - weakify
/** 弱引用 */
#define ms_weakify(var) __weak typeof(var) AHKWeak_##var = var;
#define ms_weakSelf ms_weakify(self);
/**强引用 */
#define ms_strongify(var) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
__strong typeof(var) var = AHKWeak_##var; \
_Pragma("clang diagnostic pop")
#define ms_strongSelf ms_strongify(self);

#pragma mark - 查看代码运行时间(只要在需要计算时间的代码块前后写上TICK,TOCK宏即可)
/** 打勾子 */
#define MS_TICK    NSDate *startTime = [NSDate date];
/** 输出代码运行时间 */
#define MS_TOCK    MSLog(@"Time: %f", -[startTime timeIntervalSinceNow]);


#pragma mark - 图片地址处理
/** string转URL */
static inline NSURL* MSURL(NSString *url)
{
    NSString *str = @"";
    if ([url hasPrefix:@"www"] || [url hasPrefix:@"test"])
    {
        url = [@"https://" stringByAppendingString:url];
    }
    else if ([url hasPrefix:@"/oss/"])
    {
        str = [API_BASE_URL_STRING stringByAppendingString:url];
    }
    else
    {
        str = url;
    }
    
    return [NSURL URLWithString:str] ?: [NSURL URLWithString:[str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
}


#pragma mark - ERROR_MESSAGE
/** errorCode转文字 */
static inline NSString* ms_error_message(NSInteger errorCode)
{
    NSString *message;
    switch (errorCode)
    {
        case -1001:
            message = @"请求超时";
            break;
        case -1004:
            message = @"未能连接到服务器";
            break;
        case -1009:
            message = @"网络丢失，请检查网络";
            break;
        default:
            message = @"加载失败";
            break;
    }
    
    return message;
}


#endif /* MSMacro_h */

